#ifndef ILRT_STRING_H_
#define ILRT_STRING_H_

#include <ilrt/Type.h>
#include <ilrt/Collection.h>
#include <ilrt/Allocator.h>
#include <illib/RedBlackTree.h>


namespace ilrt{
	class String : public Array<char> {
	protected:
		~String();
	public:
		String();
		char * string();
	};

	namespace StringCache{
		class Entry : public String {
		private:
			Entry(const Entry &other);
		protected:
			uint32_t hash_;
			friend class StringTreeFunctions;
			friend class Cache;
		public:
			Entry();
			void setup(char * string, size_t length, uint32_t hash);
			~Entry();
		};

		class StringTree : public illib::RedBlackTree::Tree<Entry> {
		private:
			StringTree(const Entry &other);
		protected:
			StringTree();
			friend class Cache;
		public:
		};

		class StringTreeFunctions : public illib::RedBlackTree::Functions<Entry>{
		public:
			virtual bool lesser(StringTree::NodeType &left, StringTree::NodeType &right);
			virtual bool greater(StringTree::NodeType &left, StringTree::NodeType &right);
			virtual bool equal(StringTree::NodeType &left, StringTree::NodeType &right);
		};

		class Cache{
		private:
			Cache(const Entry &other);
		protected:
			StringTree stringTree_;
			friend class StringTree;
		public:
			Cache();
			void clear();
			String * get(char * string);
			String * get(String & string);
			String * get(char * string, size_t length);
			String & add(illib::Allocator &allocator, char * string);
			String & add(illib::Allocator &allocator, char * string, size_t length);
			String & add(illib::Allocator &allocator, String& string);
			String & string(illib::Allocator &allocator, String& str);
			String & string(illib::Allocator &allocator, char * str);
			String & string(illib::Allocator &allocator, char * str, size_t length);
		};
	};

	class StringType : public ArrayType<char> {
	protected:
		Allocator::PoolAllocator<illib::RedBlackTree::Node<StringCache::Entry> > cacheAllocator_;
		StringCache::Cache cache_;
	public:
		StringType(Runtime & runtime) : 
			ArrayType<char>(runtime),
			cacheAllocator_(0, "String allocator")
		{
		}
		virtual ~StringType();
		String & intern(String & string);
		String & intern(char * string);
		String & intern(char * string, size_t length);
		virtual void destroyType(){
			cache_.clear();
		}
		virtual BasicTypedPointer _create()
		{
			return BasicTypedPointer(&allocator_.create(), *this);
		}
		virtual void _destroy(BasicPointer value)
		{
			illib::MemoryTracker::tracker().release(value._value());
		}
		virtual const char * name(){
			return "String";
		}
	};
}

#endif
